import sys
import os
import sqlite3
import threading
import queue

thisDir = os.path.split(os.path.realpath(__file__))[0]
sys.path.append(os.path.join(thisDir, "..", "server"))
sys.path.append(os.path.join(thisDir, "..", "common"))

import EJOConfig
import EJOConst

from EJOServerInitializer import EJOServerInitializer
from SessionManager import SessionManager

import logging
logger = logging.getLogger(__name__)

class EJODbEngine(EJOServerInitializer):
    def __init__(self):
        logger.debug("[EJODbEngine.EJODbEngine]")
        super().__init__()
        self.__cmdQueue = queue.Queue()
        self.__resultQueue = queue.Queue()
        self.__thread = None

    def Initialize(self):
        logger.debug("[EJODbEngine.Initialize]")
        return self.__initDB()

    def Execute(self, sql):
        logger.debug(f"[EJODbEngine.Execute] {sql}")
        self.__cmdQueue.put(sql)
        self.__cmdQueue.join()
        result = self.__resultQueue.get()
        for row in result:
            yield row

    def Close(self):
        self.__cmdQueue.put("quit")

    def __initDB(self):
        try:
            self.__thread = threading.Thread(target = self.__runDB, daemon = True)
            self.__thread.start()
            SessionManager().SetProperty(EJOConst.SESSION_PROPERTY_DB, self)
            return True
        except Exception as e:
            logger.warning(f"Start DB thread exception: {e}")
        return False

    def __runDB(self):
        try:
            conn = sqlite3.connect(EJOConfig.DB_PATH)
            logger.debug(f"DB connected: {EJOConfig.DB_PATH}")
            while True:
                item = self.__cmdQueue.get()
                if item == "quit":
                    self.__cmdQueue.task_done()
                    break
                cursor = conn.cursor().execute(item)
                result = []
                for row in cursor:
                    result.append(row)
                self.__resultQueue.put(result)
                self.__cmdQueue.task_done()
            logger.debug(f"DB close: {EJOConfig.DB_PATH}")
            conn.close()
        except Exception as e:
            logger.warning(f"Run DB exception: {EJOConfig.DB_PATH}, exception: {e}")

    def __del__(self):
        logger.debug("[EJODbEngine.~EJODbEngine]")
        self.Close()
        if self.__thread:
            self.__thread.join()
